// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_GRAPH_VISUALIZER_H_
#define V8_COMPILER_GRAPH_VISUALIZER_H_

#include <stdio.h>
#include <fstream> // NOLINT(readability/streams)
#include <iosfwd>
#include <memory>

#include "src/globals.h"
#include "src/handles.h"

namespace v8 {
namespace internal {

    class OptimizedCompilationInfo;
    class SharedFunctionInfo;
    class SourcePosition;
    namespace compiler {

        class Graph;
        class Instruction;
        class InstructionBlock;
        class InstructionOperand;
        class InstructionSequence;
        class NodeOrigin;
        class NodeOriginTable;
        class RegisterAllocationData;
        class Schedule;
        class SourcePositionTable;

        struct TurboJsonFile : public std::ofstream {
            TurboJsonFile(OptimizedCompilationInfo* info, std::ios_base::openmode mode);
            ~TurboJsonFile() override;
        };

        struct TurboCfgFile : public std::ofstream {
            explicit TurboCfgFile(Isolate* isolate = nullptr);
            ~TurboCfgFile() override;
        };

        struct SourcePositionAsJSON {
            explicit SourcePositionAsJSON(const SourcePosition& sp)
                : sp(sp)
            {
            }
            const SourcePosition& sp;
        };

        V8_INLINE V8_EXPORT_PRIVATE SourcePositionAsJSON
        AsJSON(const SourcePosition& sp)
        {
            return SourcePositionAsJSON(sp);
        }

        struct NodeOriginAsJSON {
            explicit NodeOriginAsJSON(const NodeOrigin& no)
                : no(no)
            {
            }
            const NodeOrigin& no;
        };

        V8_INLINE V8_EXPORT_PRIVATE NodeOriginAsJSON AsJSON(const NodeOrigin& no)
        {
            return NodeOriginAsJSON(no);
        }

        std::ostream& operator<<(std::ostream& out, const SourcePositionAsJSON& pos);

        // Small helper that deduplicates SharedFunctionInfos.
        class V8_EXPORT_PRIVATE SourceIdAssigner {
        public:
            explicit SourceIdAssigner(size_t size)
            {
                printed_.reserve(size);
                source_ids_.reserve(size);
            }
            int GetIdFor(Handle<SharedFunctionInfo> shared);
            int GetIdAt(size_t pos) const { return source_ids_[pos]; }

        private:
            std::vector<Handle<SharedFunctionInfo>> printed_;
            std::vector<int> source_ids_;
        };

        void JsonPrintAllSourceWithPositions(std::ostream& os,
            OptimizedCompilationInfo* info,
            Isolate* isolate);

        void JsonPrintFunctionSource(std::ostream& os, int source_id,
            std::unique_ptr<char[]> function_name,
            Handle<Script> script, Isolate* isolate,
            Handle<SharedFunctionInfo> shared,
            bool with_key = false);
        std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info,
            const char* optional_base_dir,
            const char* phase,
            const char* suffix);

        struct GraphAsJSON {
            GraphAsJSON(const Graph& g, SourcePositionTable* p, NodeOriginTable* o)
                : graph(g)
                , positions(p)
                , origins(o)
            {
            }
            const Graph& graph;
            const SourcePositionTable* positions;
            const NodeOriginTable* origins;
        };

        V8_INLINE V8_EXPORT_PRIVATE GraphAsJSON AsJSON(const Graph& g,
            SourcePositionTable* p,
            NodeOriginTable* o)
        {
            return GraphAsJSON(g, p, o);
        }

        V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
            const GraphAsJSON& ad);

        struct AsRPO {
            explicit AsRPO(const Graph& g)
                : graph(g)
            {
            }
            const Graph& graph;
        };

        V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const AsRPO& ad);

        struct AsC1VCompilation {
            explicit AsC1VCompilation(const OptimizedCompilationInfo* info)
                : info_(info)
            {
            }
            const OptimizedCompilationInfo* info_;
        };

        struct AsScheduledGraph {
            explicit AsScheduledGraph(const Schedule* schedule)
                : schedule(schedule)
            {
            }
            const Schedule* schedule;
        };

        std::ostream& operator<<(std::ostream& os, const AsScheduledGraph& scheduled);
        struct AsC1V {
            AsC1V(const char* phase, const Schedule* schedule,
                const SourcePositionTable* positions = nullptr,
                const InstructionSequence* instructions = nullptr)
                : schedule_(schedule)
                , instructions_(instructions)
                , positions_(positions)
                , phase_(phase)
            {
            }
            const Schedule* schedule_;
            const InstructionSequence* instructions_;
            const SourcePositionTable* positions_;
            const char* phase_;
        };

        struct AsC1VRegisterAllocationData {
            explicit AsC1VRegisterAllocationData(
                const char* phase, const RegisterAllocationData* data = nullptr)
                : phase_(phase)
                , data_(data)
            {
            }
            const char* phase_;
            const RegisterAllocationData* data_;
        };

        std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac);
        std::ostream& operator<<(std::ostream& os, const AsC1V& ac);
        std::ostream& operator<<(std::ostream& os,
            const AsC1VRegisterAllocationData& ac);

        struct InstructionOperandAsJSON {
            const InstructionOperand* op_;
            const InstructionSequence* code_;
        };

        std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o);

        struct InstructionAsJSON {
            int index_;
            const Instruction* instr_;
            const InstructionSequence* code_;
        };
        std::ostream& operator<<(std::ostream& os, const InstructionAsJSON& i);

        struct InstructionBlockAsJSON {
            const InstructionBlock* block_;
            const InstructionSequence* code_;
        };

        std::ostream& operator<<(std::ostream& os, const InstructionBlockAsJSON& b);

        struct InstructionSequenceAsJSON {
            const InstructionSequence* sequence_;
        };
        std::ostream& operator<<(std::ostream& os, const InstructionSequenceAsJSON& s);

    } // namespace compiler
} // namespace internal
} // namespace v8

#endif // V8_COMPILER_GRAPH_VISUALIZER_H_
